package com.atguigu.gmall.product.service.impl;
import java.math.BigDecimal;

import com.atguigu.gmall.item.to.CategoryView;
import com.atguigu.gmall.product.entity.*;
import com.atguigu.gmall.product.service.*;
import com.atguigu.gmall.search.SearchAttr;
import com.atguigu.starter.cache.service.CacheService;
import com.google.common.collect.Lists;
import java.util.Date;

import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.feign.search.SearchFeignClient;
import com.atguigu.gmall.product.vo.SaveSkuVo;
import com.atguigu.gmall.search.Goods;
import com.atguigu.starter.cache.service.BitmapService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.gmall.product.mapper.SkuInfoMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
* @author lfy
* @description 针对表【sku_info(库存单元表)】的数据库操作Service实现
* @createDate 2023-08-14 16:26:08
*/
@Slf4j
@Service
public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoMapper, SkuInfo>
    implements SkuInfoService{


    @Autowired
    SkuImageService skuImageService;

    @Autowired
    BaseTrademarkService baseTrademarkService;

    @Autowired
    SkuAttrValueService skuAttrValueService;

    @Autowired
    SkuSaleAttrValueService skuSaleAttrValueService;

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    BitmapService bitmapService;


    @Autowired
    BaseCategory1Service baseCategory1Service;

    @Autowired
    SearchFeignClient searchFeignClient;

    @Autowired
    ThreadPoolExecutor executor;

    @Autowired
    CacheService cacheService;

    @Transactional
    @Override
    public void saveSkuInfo(SaveSkuVo vo) {

        //1、保存sku基本信息： sku_info
        SkuInfo skuInfo = new SkuInfo();
        BeanUtils.copyProperties(vo,skuInfo);
        save(skuInfo);

        //获取自增id
        Long skuId = skuInfo.getId();

        //2、保存sku图片信息：sku_image
        List<SkuImage> skuImages = vo.getSkuImageList().stream()
                .map(item -> {
                    SkuImage image = new SkuImage();
                    image.setSkuId(skuId);
                    image.setImgName(item.getImgName());
                    image.setImgUrl(item.getImgUrl());
                    image.setSpuImgId(item.getSpuImgId());
                    image.setIsDefault(item.getIsDefault());
                    return image;
                }).collect(Collectors.toList());
        skuImageService.saveBatch(skuImages);

        //3、保存sku的平台属性名和值： sku_attr_value
        List<SkuAttrValue> skuAttrValues = vo.getSkuAttrValueList().stream()
                .map(item -> {
                    SkuAttrValue attrValue = new SkuAttrValue();
                    attrValue.setAttrId(item.getAttrId());
                    attrValue.setValueId(item.getValueId());
                    attrValue.setSkuId(skuId);
                    return attrValue;
                }).collect(Collectors.toList());

        skuAttrValueService.saveBatch(skuAttrValues);


        //4、保存sku的销售属性名和值： sku_sale_attr_value
        List<SkuSaleAttrValue> skuSaleAttrValues = vo.getSkuSaleAttrValueList().stream()
                .map(item -> {
                    SkuSaleAttrValue saleAttrValue = new SkuSaleAttrValue();
                    saleAttrValue.setSkuId(skuId);
                    saleAttrValue.setSpuId(vo.getSpuId());
                    saleAttrValue.setSaleAttrValueId(item.getSaleAttrValueId());
                    return saleAttrValue;
                }).collect(Collectors.toList());
        skuSaleAttrValueService.saveBatch(skuSaleAttrValues);


    }

    @Override
    public void initSkuIdsBitMap() {
        //1、查询出所有skuid
        List<Long> ids = lambdaQuery()
                .select(SkuInfo::getId)
                .list()
                .stream()
                .map(SkuInfo::getId)
                .collect(Collectors.toList());

        //2、初始化位图
        ids.forEach(item->{
            //去位图占位
            redisTemplate.opsForValue().setBit(RedisConst.BITMAP_SKUIDS,item,true);
        });

        log.info("位图初始化完成：总计商品：【{}】 件",ids.size());
    }

    @Override
    public void onSale(Long skuId) {
        //上架：把商品上到检索系统
        boolean update = lambdaUpdate()
                .set(SkuInfo::getIsSale, 1)
                .eq(SkuInfo::getId, skuId)
                .update();

        //上架的商品加入到位图
        bitmapService.setbit(RedisConst.BITMAP_SKUIDS,skuId,true);

        //把这个商品的数据保存到 ES
        Goods goods = prepareGoods(skuId);
        searchFeignClient.saveGoods(goods);
    }

    /**
     * 商品下架
     * @param skuId
     */
    @Override
    public void cancelSale(Long skuId) {
        //下架：更新数据库
        boolean update = lambdaUpdate()
                .set(SkuInfo::getIsSale, 0)
                .eq(SkuInfo::getId, skuId)
                .update();


        //下架的商品要从位图移除
        bitmapService.setbit(RedisConst.BITMAP_SKUIDS,skuId,false);

        //把这个商品的数据从ES中移除
        searchFeignClient.delete(skuId);


        //【业务保证数据最终一致性】
        //删除redis中缓存的sku数据
        cacheService.delayDoubleDel(RedisConst.SKU_INFO_CACHE_KEY+skuId,10L);

    }


    /**
     * 准备远程检索用的商品数据
     * @param skuId
     * @return
     */
    private Goods prepareGoods(Long skuId) {
        Goods goods = new Goods();
        //1、封装商品基本信息
        CompletableFuture<SkuInfo> skuInfoFuture = CompletableFuture.supplyAsync(() -> {
            SkuInfo skuInfo = getById(skuId);
            goods.setId(skuInfo.getId());
            goods.setDefaultImg(skuInfo.getSkuDefaultImg());
            goods.setTitle(skuInfo.getSkuName());
            goods.setPrice(skuInfo.getPrice());
            goods.setCreateTime(new Date());
            return skuInfo;
        }, executor);


        //2、准备品牌数据
        CompletableFuture<Void> trademarkFuture = skuInfoFuture.thenAcceptAsync(result -> {
            BaseTrademark trademark = baseTrademarkService.getById(result.getTmId());
            goods.setTmId(result.getTmId());
            goods.setTmName(trademark.getTmName());
            goods.setTmLogoUrl(trademark.getLogoUrl());
        },executor);


        //3、准备分类层级数据
        CompletableFuture<Void> categoryViewFuture = skuInfoFuture.thenAcceptAsync(result -> {
            CategoryView categoryView = baseCategory1Service.getCategoryView(result.getCategory3Id());
            goods.setCategory1Id(categoryView.getCategory1Id());
            goods.setCategory1Name(categoryView.getCategory1Name());
            goods.setCategory2Id(categoryView.getCategory2Id());
            goods.setCategory2Name(categoryView.getCategory2Name());
            goods.setCategory3Id(categoryView.getCategory3Id());
            goods.setCategory3Name(categoryView.getCategory3Name());
            goods.setHotScore(0L);
        }, executor);


        //4、当前商品的平台属性名和值
        CompletableFuture<Void> attrFuture = CompletableFuture.runAsync(() -> {
            List<SearchAttr> attrs = skuAttrValueService.getSkuAttrAndValue(skuId);
            goods.setAttrs(attrs);
        }, executor);

        CompletableFuture.allOf(trademarkFuture,categoryViewFuture,attrFuture)
                .join();


        return goods;
    }
}




